/**
 * 考虑到原始DP，Diabc记录S[1...i]之间序列abc的数量
 * 到第i个位置时，只会影响到D[i][a][b][S[i]]的值，其余Diab[...]的值不会变
 * 因此实际上不要四维DP，三维就够了。
 * 
 * 令Diab记录S[1...i]之间序列 `abSi`的数量
 * 令Uiab记录S[1...i]之间序列`ab`的数量.
 * 令Cnt[i][c]记录S[1...i]之间字符c的数量
 * 可以依次求出
 * 
 * 再使用Pos[c]记录字符c在S中的位置，显然是一个升序数组
 * 
 * 对每一个询问(L, R, abc):
 * 在Pos[c]中求出[L, R]中的最后一个位置，以及之前的最靠近L的位置，
 * 分别记作last与first
 * D[last][a][b]记录了S[1...last]中abc的数量
 * 再排除非法的即可。非法的情况分为3种：
 * 1. abc全部位于L之前的
 * 2. a位于L之前、bc位于[L....R]之中的
 * 3. ab位于L之前、c位于之中的。
 * 
 * O(26^3 * N + QlogN)
 * 1244ms，与分块差不多 
 */
#include <bits/stdc++.h>
using namespace std;

using llt = long long;
using arint = array<int, 27>;
using arll = array<llt, 27>;
using aall = array<arll, 27>;

int N;
int Q;
string S;
int BlockSize;
int BlockCnt;

array<vector<int>, 27> Pos;
vector<array<int, 27>> Cnt;
vector<aall> D;
vector<aall> U;

void init(){
	Cnt.clear(); Cnt.reserve(N + 1);
	Cnt.emplace_back(array<int, 27>{0});

	for(int i=1;i<=26;++i) Pos[i].emplace_back(0);

	U.clear(); U.reserve(N + 1);
	U.emplace_back(aall{arll{0LL}});

    for(int i=1;i<=N;++i){
		auto c = S[i] - 'a' + 1;
		Pos[c].emplace_back(i);
		
		U.emplace_back(U.back());
        for(int j=1;j<=26;++j){
            U[i][j][c] += Cnt[i - 1][j];
		}

		Cnt.emplace_back(Cnt.back());
		++Cnt.back()[c];
	}

	D.assign(N + 1, aall{arll{0LL}});

    const auto & cn = Cnt[N];
	for(int i=3;i<=N;++i){
		auto c = S[i] - 'a' + 1;

        for(int a=1;a<=26;++a){
			for(int b=1;b<=26;++b){
				D[i][a][b] += U[i - 1][a][b];
			}
		}
 	}
    
	for(int i=1;i<=26;++i){
		for(auto it=++Pos[i].begin(),et=Pos[i].end();it!=et;++it){
			const auto & pre = D[*(it-1)];
			auto & d = D[*it];
			for(int a=1;a<=26;++a){
				for(int b=1;b<=26;++b){
                    d[a][b] += pre[a][b]; 
				}
			}
		}
	}
    	 

	// for(int i=1;i<=N;++i){
	// 	for(int a=1;a<=26;++a){
	// 		for(int b=1;b<=26;++b){
	// 			if(D[i][a][b]){
	// 				cout << "(" << i << ", " << (char)(a+'a'-1) << S[i] << (char)(b+'a'-1) << ", " << D[i][a][b] << ")";
	// 			}
	// 		}
	// 	}
	// 	cout << endl;
	// } 

	// for(int i=1;i<=N;++i){
	// 	cout << i << ": ";
	// 	for(int a=1;a<=26;++a){
	// 		for(int b=1;b<=26;++b){
	// 			if(U[i][a][b]){
	// 				cout << "(" << (char)(a+'a'-1) << (char)(b+'a'-1) << ", " << U[i][a][b] << ")";
	// 			}
	// 		}
	// 	}
	// 	cout << endl;
	// }

    return;
}

int L, R;
char T[5];

llt proc(){
	if(L + 1 >= R) return 0;

    int a = T[0] - 'a' + 1;
	int b = T[1] - 'a' + 1;
	int c = T[2] - 'a' + 1;

    const auto & posc = Pos[c];
	auto pp = equal_range(posc.begin(), posc.end(), R + 1);
	int last = pp.first - posc.begin() - 1;

	pp = equal_range(posc.begin(), posc.end(), L);
	int first = pp.first - posc.begin();

	if(first > last) return 0;

	last = posc[last];
	first = posc[first - 1] + 1;

	llt ans = D[last][a][b] - D[first - 1][a][b];
	llt ca = Cnt[L - 1][a];
	llt cbc = U[R][b][c] - U[L - 1][b][c];
	cbc -= Cnt[L - 1][b] * (Cnt[R][c] - Cnt[L - 1][c] + 0LL);
	ans -= ca * cbc;

    llt cc = Cnt[R][c] - Cnt[L - 1][c];
	llt cab = U[L - 1][a][b];
	ans -= cab * cc;
	return ans;
 }

int main(){
#ifndef ONLINE_JUDGE
    freopen("z.txt", "r", stdin);
#endif
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin >> N >> Q >> S;
	S = " " + S;
    init();
    while(Q--){
        cin >> L >> R >> T;
        cout << proc() << "\n";
    }
    return 0;
}